#include "stdafx.h"
#include "FileSystem.h"
#include "StringFunction.h"
#include "BaseFunctions.h"
#include <algorithm>
#include <sys/stat.h>

#ifdef _WIN32

#define CORRECTPATH(PATH)\
	if (PATH.length() > 0){\
	Replace(PATH, "/", "\\");\
	if (PATH.at(PATH.length() - 1) == '\\')\
	PATH = PATH.substr(0, PATH.length() - 1);}\

namespace BaseFunction
{
	bool RemoveFile(std::string file)
	{
		CORRECTPATH(file);
		return ::DeleteFile(StringToWString(file).c_str()) != 0;
	}

	bool MovesFile(std::string oldFile, std::string newFile, bool shift)
	{
		CORRECTPATH(oldFile);
		CORRECTPATH(newFile);
		bool xx = CopysFile(oldFile, newFile, shift);
		bool yy = RemoveFile(oldFile);
		return xx && yy;
	}

	bool CopysFile(std::string oldFile, std::string newFile, bool shift)
	{
		CORRECTPATH(oldFile);
		CORRECTPATH(newFile);
		std::string dir = FileDirtory(newFile);
		if (ExistDirtory(dir) == false)
			MakeDirtory(dir);
		return ::CopyFile(StringToWString(oldFile).c_str(), StringToWString(newFile).c_str(), shift) != 0;
	}

	bool RenameFile(std::string oldFile, std::string newFile)
	{
		CORRECTPATH(oldFile);
		CORRECTPATH(newFile);
		return ::MoveFile(StringToWString(oldFile).c_str(), StringToWString(newFile).c_str()) != 0;
	}

	bool ExistFile(std::string file)
	{
		CORRECTPATH(file);
		DWORD result = ::GetFileAttributes(StringToWString(file).c_str());
		return result != INVALID_FILE_ATTRIBUTES && result != FILE_ATTRIBUTE_DIRECTORY;
	}

	double FileSize(std::string file)
	{
		CORRECTPATH(file);
		if (ExistFile(file))
		{
			struct stat info;
			stat(file.c_str(), &info);
			return info.st_size;
		}
		return 0;
	}

	std::string FileSizeString(std::string file)
	{
		CORRECTPATH(file);
		double size = FileSize(file);
		std::string units[4] = {" bytes", " KB", " MB", " GB"};
		int i = 0;
		for (; i < 4 && size > 1024; ++i)
			size /= 1024;
		return ConvertToString(size) + units[i];
	}

	std::string FileName(std::string file)
	{
		CORRECTPATH(file);
		return BaseFileName(file) + "." + ExtensionFileName(file);
	}

	std::string BaseFileName(std::string file)
	{
		CORRECTPATH(file);
		if (ExistFile(file))
		{
			std::string::size_type start = file.rfind('\\');
			std::string::size_type end = file.rfind('.');
			return file.substr(start + 1, end - start - 1);
		}
		return "";
	}

	std::string ExtensionFileName(std::string file)
	{
		CORRECTPATH(file);
		if (ExistFile(file))
		{
			std::string::size_type pos = file.rfind('.');
			return file.substr(pos + 1, file.length() - pos);
		}
		return "";
	}

	std::string FileDirtory(std::string file)
	{
		CORRECTPATH(file);
		std::string::size_type pos = file.rfind('\\');
		return file.substr(0, pos);
	}

	std::vector<std::string> FindFiles(std::string dir, std::string filter)
	{
		CORRECTPATH(dir);
		std::string dirtory = dir;
		if (dirtory.at(dirtory.length() - 1) != '\\')
			dirtory = dirtory + "\\";

		std::wstring serchname = StringToWString(dirtory + filter);
		std::vector<std::string> list;
		WIN32_FIND_DATA info;
		HANDLE handle = ::FindFirstFile(serchname.c_str(), &info);
		if (handle && handle != INVALID_HANDLE_VALUE)
		{
			std::string name = WStringToString(info.cFileName);
			if (name != "." && name != "..")
				list.push_back(dirtory + name);

			while (::FindNextFile(handle, &info))
			{
				std::string name = WStringToString(info.cFileName);
				if (name != "." && name != "..")
					list.push_back(dirtory + name);
			}
			::FindClose(handle);
		}
		return list;
	}

	bool ExistDirtory(std::string dir)
	{
		CORRECTPATH(dir);
		DWORD result = ::GetFileAttributes(StringToWString(dir).c_str());
		return result != INVALID_FILE_ATTRIBUTES && result == FILE_ATTRIBUTE_DIRECTORY;
	}

	bool DeleteDirtory(std::string dir)
	{
		CORRECTPATH(dir);
		if (ExistDirtory(dir) == false)
			return false;

		std::vector<std::string> files = FindFiles(dir, "*.*");
		for (std::vector<std::string>::iterator iter = files.begin(); iter != files.end(); ++iter)
		{
			if (ExistDirtory(*iter))
			{
				if (FindFiles(*iter, "*.*").size() != 0)
					DeleteDirtory(*iter);
				::RemoveDirectory(StringToWString(*iter).c_str());
			}
			if (ExistFile(*iter))
				RemoveFile(*iter);
		}
		::RemoveDirectory(StringToWString(dir).c_str());
		return true;
	}

	bool CopyDirtory(std::string oldDirtory, std::string newDirtory, std::string filter, bool shift, bool keep)
	{
		CORRECTPATH(oldDirtory);
		CORRECTPATH(newDirtory);
		if (ExistDirtory(oldDirtory) == false)
			return false;

		MakeDirtory(newDirtory);
		std::vector<std::string> tmp = FindFiles(oldDirtory, "*.");
		std::vector<std::string> files = FindFiles(oldDirtory, filter);
		for (std::vector<std::string>::iterator iter = tmp.begin(); iter != tmp.end(); ++iter)
			files.push_back(*iter);

		std::string tmpdir = newDirtory;
		Replace(tmpdir, "*", "");
		for (std::vector<std::string>::iterator iter = files.begin(); iter != files.end(); ++iter)
		{
			if (ExistDirtory(*iter))
				CopyDirtory(*iter, newDirtory + "*" + (*iter).substr((*iter).rfind("\\")), filter, shift, keep);
			if (ExistFile(*iter))
			{
				std::string name = FileName(*iter);
				if (keep)
					CopysFile(*iter, tmpdir + "\\" + name, shift);
				else
					CopysFile(*iter, newDirtory.substr(0, newDirtory.find("*")) + "\\" + name, shift);
			}
		}
		return true;
	}

	bool MoveDirtory(std::string oldDirtory, std::string newDirtory)
	{
		CORRECTPATH(oldDirtory);
		CORRECTPATH(newDirtory);
		bool xx = CopyDirtory(oldDirtory, newDirtory);
		bool yy = DeleteDirtory(oldDirtory);
		return xx && yy;
	}

	std::string SystemTempDirtory()
	{
		wchar_t shortname[MAX_PATH];
		wchar_t longname[MAX_PATH];
		memset(shortname, 0, sizeof(shortname));
		memset(longname, 0, sizeof(longname));
		::GetTempPath(MAX_PATH, shortname);
		::GetLongPathName(shortname, longname, MAX_PATH);
		return WStringToString(std::wstring(longname));
	}

	bool MakeDirtory(std::string dir)
	{
		CORRECTPATH(dir);
		dir = dir + "\\";
		std::string::size_type pos = dir.find("\\");
		while (pos != std::string::npos)
		{
			std::string path = dir.substr(0, pos);
			if (ExistDirtory(path) == false)
			{
				bool result = ::CreateDirectory(StringToWString(path).c_str(), NULL) != 0;
				if (result == false)
					return false;
			}
			pos = dir.find("\\", pos + 1);
		}
		return true;
	}

	std::string ModuleFullPath(void* pModule)
	{
		HMODULE module = (HMODULE)pModule;
		wchar_t buffer[512];
		memset(buffer, 0, sizeof(buffer));
		::GetModuleFileName(module, buffer, 512);
		return WStringToString(buffer);
	}

	std::string ModuleDirtory(void* pModule)
	{
		return FileDirtory(ModuleFullPath(pModule));
	}
}
#endif